<template>
  <div class="p-compDesign">
    <!--控件分类表      -->
    <Tabs :value="$t(`compDesign.jProperty.component`)" class="component">
      <TabPane :label="$t(`compDesign.jProperty.component`)" :name="$t(`compDesign.jProperty.component`)"
        ><jComp ref="comp"></jComp
      ></TabPane>
    </Tabs>
    <div class="content">
      <!-- 组件工具栏     -->
      <jHeader
        ref="header"
        style="grid-area: head;"
        @openConfig="toolShow=true"
        @saveConfig="saveConfig"
        @getPage="getPage"
        @newPage="newPage"
        @refreshPage="refreshPage"
        @deletePage="deleteModule"
      >
      </jHeader>
      <jEditArea
        v-show="refresh&&!!compGroup.currentId"
        ref="editArea"
        :compGroup="compGroup"
        :currentModule="currentModule"
        :currentModuleId="currentModuleId"
        :key="currentModuleId"
      ></jEditArea>
      <starMenu ref="slotMenu" :e="e" :title="'slot'" style="width:100px" @on-select="selectSlot">
        <menuItem v-for="(item,i) in slotItem" :name="item" :key="i" style="padding:2px 24px;">{{item}}</menuItem>
        <Divider style="margin-top:2px;margin-bottom: 2px;"></Divider>
        <menuItem style="color: darkgray;padding:2px 24px;" name="cancel">Cancel</menuItem>
      </starMenu>
      <starMenu :e="contextmenuE" :style="{width:'100px'}" @on-select="selectRightClick" transfer>
        <menuItem style="color: darkblue;padding:2px 24px; " name="edit">{{$t(`compDesign.jProperty.edit`)}}</menuItem>
        <Divider style="margin-top:2px;margin-bottom: 2px;"></Divider>
        <menuItem
          style="color: #ed4014;padding:2px 24px;"
          name="delete"
          >{{$t(`compDesign.jProperty.delete`)}}</menuItem
        >
        <Divider style="margin-top:2px;margin-bottom: 2px;"></Divider>
        <menuItem
          style="color: darkgray;padding:2px 24px;"
          name="cancel"
          >{{$t(`compDesign.jProperty.cancel`)}}</menuItem
        >
      </starMenu>
      <j-config
        v-if="!!currentModule && !!compGroup"
        :toolShow="toolShow"
        :title="$t(`compDesign.jProperty.propertyConfig`)"
        :width="90"
        @submit="toolShow=false"
        @close="toolShow=false"
      ></j-config>
    </div>
  </div>
</template>

<script>
// import
import jComp from './parts/jComp';
import jHeader from './parts/jHeader';
import jEditArea from './editArea/jEditArea';
import JConfig from "./configuration/index";
import Sortable from "sortablejs";
import {mapActions, mapState} from "vuex";
import storeVar from "./mixins/storeVar";
    export default {
      name: 'jConfiguration',
      mixins:[storeVar],
      components: { JConfig, jComp, jHeader, jEditArea, },
      created() {
        this.loadModel()
        this.loadGlobalOption()
      },
      mounted() {
        /**
         * 获取所有type=module的记录，即所有页面配置记录，传给页面配置选择框
         */
        let hisSelectId = localStorage.getItem('components_selId')
        this.loadAllModules().then(m=>{
          if(m.length>0){
            this.setElement('root');
          }
          if (hisSelectId) {
            let item = JSON.parse(hisSelectId)
            let id = item
            if (Array.isArray(item) && item[1]) {
              id = item[1]
              this.getPage(id)
            }
          }
          // this.toolShow = true
        })
        this.loadRole()
      },
      beforeDestroy() {
        // this.destroy();
      },
      watch: {
        currentModule: {
          handler(val) {
            if (val && val.name) {
              document.title = '配置平台-' + val.name
            }
          }, immediate: true
        }
      },
      methods: {
        coding(){
          let _this=this;
          this.scriptValidate(this.code).then(flag=>{
            if(flag){
              _this.updateScript(this.code).then(flag=>{
                setTimeout(()=>{
                  _this.$nextTick(()=>{
                    _this.codeValidate=true;
                  })
                },0)
              })
            }
          })
        },
        /**
         * 新增配置
         */
        newPage(item, isCopy){
          let newData = {...item, value: [], config: []}
          if (isCopy && this.currentModule) {
            newData.value = this.currentModule.value
            newData.config = this.currentModule.config
          }
          console.log("file: index.vue:124  newPage  this.currentModule:", item, this.currentModule, newData)
          this.addModule(newData).then(flag=>{
            if(flag){
              this.init();
            }
          })
        },
        /**
         * 当选择某给页面配置时，加载配置，并且保存名称和id
         */
        getPage(item){
          if(!!item){
            this.getModule(item).then(flag=>{
              if(flag){
                this.init();
              }
            })
          }
        },
        /******************************************************************************************
         * 初始化步骤：只有加载页面的时候，才绑定拖拽
         * 1，设置拖拽元素
         * 2，触发编辑容器的单击方法，初始容器为编辑状态
         * ****************************************************************************************
         */
        init(){
          this.$nextTick(()=>{
            /**2,绑定拖拽元素*/
            for(let key in this.$refs.comp.$refs){
              this.$refs.comp.$refs[key].map(el=>{
                this.itemDrag(el,{})
              })
            };
            /**3,调用容器单击方法*/
            this.setElement('root');
          });
        },
        /**添加操作来自于拖拽itemDrag中的onEnd，其中先删除老的dom再触发slot菜单的显示*/
        /**
         * 设定拖动元素，及放置事件
         * @param el:元素容器设置
         * @param option:sortbalejis配置项
         * @returns {{}}
         */
        itemDrag(el,option){
          let _this=this;
          let ops = {
            animation: 100,
            sort: false,
            delay: 50,
            group: {name: 'root', pull: 'clone', put: false},
            chosenClass: 'chosenClass',
            // ghostClass: 'ghostClass',
            dragClass: 'dragClass',
            forceFallback: true,
            onEnd: function (evt) {
              /**放置发生时，设立slot菜单*/
              if(evt.from!==evt.to){
                _this.setSlotSelectionPanel(evt.originalEvent.clientX,evt.originalEvent.clientY);
                _this.category=evt.item.dataset.category;
                _this.tagName=evt.item.dataset.name;
                _this.jquery(evt.item).remove();
              }
            }
          };
          this.itemSortable = Sortable.create(el, Object.assign(ops,option));
        },
        /******************************************************************************************
         * viewProperties数组的添加操作
         * ****************************************************************************************
         */
        /**slot菜单的显示*/
        /**
         * 设置slot菜单模板的显示内容、位置
         * @param top
         * @param left
         */
        setSlotSelectionPanel(clientX,clientY){
          this.slotName=null;
          if(this.compGroup.currentId==='root'){
            this.slotItem=['default'];
          }else{
            let classObject=this.compGroup.getClassObject(this.compGroup.currentId);
            this.slotItem=classObject.slot;
          }
          if(this.slotItem.length>0){
            this.$set(this.e, 'show', true);
            this.$set(this.e, 'clientX', clientX);
            this.$set(this.e, 'clientY', clientY);
          }
        },
        /**
         * 手动取消slot菜单
         */
        handleClose(){
          this.slotName=null;
          this.$set(this.e,'show',false);
        },
        /**slot菜单中选择插槽，触发对viewProperties的添加*/
        /**
         * 选中slot，并且添加新控件
         * @param e
         * @param item
         */
        selectSlot(item){
          if(!item||item==='cancel'){
            this.handleClose();
            return;
          }
          this.slotName=item;
          this.addElementIntoGroup(this.compGroup.currentId,this.tagName,this.slotName);
          this.handleClose();
        },
        /**对viewProperties的添加操作，需要通过refresh的切换，更新编辑区的显示，由此触发所有控件的状态初始化*/
        /**
         * propertyTpl是控件属性模板,结构为{attrs:[{name:'',value:'',editor:'',option:[]}],props:[],style:[],on:[],nativeOn:[]}。
         * 当形成实例，需要形成具有id，parentId信息的层级数据
         * 该方法是通过parentId及propertyTpl构造为viewProperties数据
         * @param category:控件分类
         * @param tag：控件名称
         * @param parentId：父级id
         */
        addElementIntoGroup(parentId,tag,slotName){
          let _this=this;
          this.addElement({parentId,tag,slotName}).then(id=>{
            this.setElement(id)
          })
        },
        /******************************************************************************************
         * viewProperties数组的更新操作
         * ****************************************************************************************
         */
        /**
         * 来自属性面板的属性提交事件，更新后需要调用初始化setCurrentEl
         * @param data
         */
        async saveProperties(){
          // if(!!this.$refs.jApi){
          //   this.$refs.jApi.addApiData()
          // }
          // this.updateProperties().then(flag=>{
          //   if(flag){
          //     this.setElement(this.compGroup.currentId);
          //     this.toolShow=false;
          //   }
          // })
          // this.toolShow=false;
          // console.log(this.viewProperties)
        },
        /******************************************************************************************
         * viewProperties数组的删除操作
         * ****************************************************************************************
         */
        /**
         * 选中slot，并且添加新控件
         * @param e
         * @param item
         */
        selectRightClick(item){
          if(!item||item==='cancel'){
            this.$set(this.contextmenuE,'show',false);
            return;
          }else if(!item||item==='edit'){
            this.toolShow=true;
            this.$set(this.contextmenuE,'show',false);
            return;
          };
          this.deleteElement(this.compGroup.currentId).then(flag=>{
            if(flag){
              this.setElement('root');
            }
          });
          this.$set(this.contextmenuE,'show',false);
        },
        saveConfig() {
          this.updateModule().then(flag => {
            flag && this.$Message.success(this.lang.saveSucc)
          })
        },
        async refreshPage() {
          let flag = await this.refreshModules()
          await this.loadModel()
          flag && this.$Message.success(this.lang.refreshSucc)
        },
        // modelChange(data){
        //   this.autoSetField(data)
        // }
        ...mapActions('compDesign/config',[
          'loadAllModules',//加载所有页面配置
          'refreshModules',//刷新所有页面配置
          'getModule',//按id获取当前页面配置
          'addModule',//新增页面配置
          'updateModule',//保存页面配置
          'deleteModule',//删除当前页
          'addElement',//添加元素
          'updateProperties',//更新属性
          'updateScript',//更新属性
          'updateApi',//更新属性
          'scriptValidate',//更新属性
          'destroy',
        ]),
        ...mapActions('admin/model',[
          'loadModel',
          'loadGlobalOption'
        ]),
        ...mapActions('admin/layout', [
          'loadRole'
        ])
      },
      data(){
        return {
          code:this.script,
          codeValidate:true,
          /*****************************************************************************************************
           * 数据viewProperties是核心数据，围绕它的数据操作包括：
           * 拖拽添加，控件右键删除、资产树右键删除，属性修改提交
           * 每次编辑后需要切换refresh来更新编辑区显示状态
           * ***************************************************************************************************
           * */
          /**viewProperties以配置数组形式存放页面控件组
           * 每项数据格式为{id:'',parentId:'',tag:'',properties:{attrs:[{name:'',value:'',editor:'',option:[]}],props:[],style:[],on:[],nativeOn:[]}}
           * */
          /**变更数据时的刷新*/
          refresh:true,
          /**当前选中的控件id，只有选中控件时，才更新控件拖拽绑定，才显示相关属性*/
          toolShow:false,
          itemSortable:null,
          currentSortable:null,
          parentSortable:null,
          /*****************************************************************************************************
           * 数据viewProperties的拖拽添加操作
           * 拖拽时，onEnd为释放，释放后需要在slot菜单中选择插槽，e为slot菜单显示控制，slotItem为父级控件的slot清单，slotName为选中的slot名称
           * 拖拽后删除原有dom，并且保存控件配置的索引：category,tageName
           * ***************************************************************************************************
           * */
          /**slot选择菜单：是否显示、选择清单、选中slot名称*/
          e:{
            show:false,
            clientX:0,
            clientY:0
          },
          slotItem:[],
          slotName:null,
          /**最新添加的控件分类：大类、控件名称*/
          category:null,
          tagName:null,
        }
      },
      computed:{
        ...mapState('compDesign/config',[
            'modules',  //所有组件配置
            'modulesTree',//所有组件配置, tree结构
            'currentModule',//当前组件配置
            'currentModuleId',//当前组件id
            'script',//当前页面脚本
            'extendField',//当前页面扩展字段，新数据源
        ]),
        ...mapState('admin/model', [
          'globalOption'
        ]),
        lang() {
          return {
            "en-US": {
              saveSucc: "save success!",
              refreshSucc: "refresh success!",
            },
            "zh-CN": {
              saveSucc: "保存成功!",
              refreshSucc: "刷新成功!",
            },
          }[this.G_Locale];
        }
      },
    }
</script>

<style lang="less">
.p-compDesign {
  height: 100%;
  padding-right: 150px;
  position: relative;
  .content {
    margin-right: 10px;
    border-radius: 2px;
    box-shadow: 2px 0 20px 0 rgba(0,0,0,.1);
  }
  .component {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 150px;
    border-radius: 2px;
    box-shadow: 2px 0 20px 0 rgba(0,0,0,.1);
    background-color: #fff;
    .ivu-collapse {
      border: none;
    }
    .ivu-tabs-content {
      height: ~"calc(100vh - 164px)";
      overflow-y: auto;
      &::-webkit-scrollbar {
        display: none;
      }
    }
  }
  // 组件相关
  // .c-cli-content-general, .c-cli-content-tow, .c-cli-content-three {
  //   height: auto;
  // }
}
</style>
